package com.plat.api.aop;

import com.plat.api.anonation.RequestLimit;
import com.plat.api.common.RespCode;
import com.plat.api.exception.PlatException;
import com.plat.framework.redis.RedisCache;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * Created with IntelliJ IDEA.
 * User: shish
 * Date: 2020/7/15
 * Time: 14:21
 * Description: No Description
 */

@Aspect
@Component
@Slf4j
public class RequestLimitContract {

    @Autowired
    private RedisCache redisCache;

    @Before("within(@org.springframework.web.bind.annotation.RestController *) && @annotation(limit)")
    public void requestLimit(final JoinPoint joinPoint, RequestLimit limit) throws PlatException {
        try {
            Object[] args = joinPoint.getArgs();
            HttpServletRequest request = null;
            for (int i = 0; i < args.length; i++) {
                if (args[i] instanceof HttpServletRequest) {
                    request = (HttpServletRequest) args[i];
                    break;
                }
            }
            if (request == null) {
                throw new PlatException("方法中缺失HttpServletRequest参数");
            }
            String ip = request.getLocalAddr();

            String url = request.getRequestURL().toString();
            String key = "req_limit_".concat(url).concat(ip);
            log.info("[访问IP地址={},访问时间={}]", ip, new Date());
            if (!redisCache.hasKey(key)) {
                redisCache.setCacheObject(key, 1);
            } else {
                redisCache.setCacheObject(key, (int) redisCache.getCacheObject(key) + 1);
            }
            int count = redisCache.getCacheObject(key);
            if (count > 0) {
                //创建一个定时器
                Timer timer = new Timer();
                TimerTask timerTask = new TimerTask() {
                    @Override
                    public void run() {
                        redisCache.deleteObject(key);
                    }
                };
                //这个定时器设定在time规定的时间之后会执行上面的remove方法，也就是说在这个时间后它可以重新访问
                timer.schedule(timerTask, limit.time());
            }
            if (count > limit.count()) {
                log.info("用户IP[" + ip + "]访问地址[" + url + "]超过了限定的次数[" + limit.count() + "]");
                throw new PlatException("HTTP请求超出设定的限制", RespCode.IP_REQUEST_LIMIT.getError_msg(), RespCode.IP_REQUEST_LIMIT.getCode());
            }
        } catch (PlatException e) {
            throw e;
        } catch (Exception e) {
            log.error("发生异常", e);
        }
    }

}
